package wsepForum.domain.handlers;

import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.Date;
import java.util.Vector;

import wsepForum.common.elements.AForumElement;
import wsepForum.common.elements.Message;
import wsepForum.common.elements.SearchResult;
import wsepForum.common.elements.Section;
import wsepForum.common.elements.Topic;
import wsepForum.common.elements.AForumElement.ForumElementType;
import wsepForum.domain.Session;
import wsepForum.domain.SessionManager;
import wsepForum.domain.exceptions.SystemFailureException;
import wsepForum.domain.exceptions.UnAuthorizedException;
import wsepForum.domain.exceptions.WrongPasswordException;
import wsepForum.persistance.IPersistentHandler;
import wsepForum.persistance.exceptions.DataBaseIOException;
import wsepForum.persistance.exceptions.WrongElementIDException;
import wsepForum.persistance.exceptions.WrongUserNameException;

/**
 * The main interface between the GUI layer and the domain layer.
 * Provides the transportation of information between the GUI and the persistent.
 * Each further inheritance implements/overrides the services a certain user group
 * can receive from the system.
 * @author Amir Harel & Ariel Rozen & Oren Ben-Haim
 */
/**
 * @author harelam
 *
 */
public abstract class AUserHandler {

	/*****************************
	 * MEMBERS                   *
	 *****************************/
	/**
	 * The interface supplied by the persistent layer.
	 */
	private IPersistentHandler persistent;
	protected final int ROOT_SECTION = 0;


	/*****************************
	 * CONSTRUCTOR               *
	 *****************************/
	public AUserHandler(IPersistentHandler persistent){
		this.persistent = persistent;
	}

	/*****************************
	 * METHODS
	 *****************************/

	/**
	 * search for messages written by authorName
	 * @param authorName - the name of the author who wrote the message
	 * @return a vector of messages that fit the query
	 */
	public Vector<SearchResult> searchByAuthor(String authorName) throws Exception{
		return this.getPersistent().searchByAuthor(authorName);
	}

	/**
	 * search for messages written in a given interval of dates
	 * @param from - the start date
	 * @param to - the end date
	 * @return a vector of messages that fit the query
	 */
	public Vector<SearchResult> searchByDate(Date from, Date to) throws Exception{
		return this.getPersistent().searchByDate(from, to);
	}

	/**
	 * search for messages containing the given sentence
	 * @param sentence - the sentence that should appear in the messages
	 * @return a vector of messages that fit the query
	 */
	public Vector<SearchResult> searchByContent(String sentence) throws Exception{
		return this.getPersistent().searchByContent(sentence);
	}

	/**
	 * @param messageID - the ID of the message requested.
	 * @return Message - the Message associated with messageID.
	 * @throws Exception
	 */
	public Message getMessage(int messageID) throws WrongElementIDException, SystemFailureException {
		try {
			return (Message)this.getPersistent().getForumElement(messageID, ForumElementType.MESSAGE);
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		}
	}

	/**
	 * @param topicID - the ID of the topic requested
	 * @return Topic - the Topic associated with TopicID
	 * @throws Exception
	 */
	public Topic getTopic(int topicID) throws WrongElementIDException, SystemFailureException {
		try {
			return (Topic)this.getPersistent().getForumElement(topicID, ForumElementType.TOPIC);
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		}
	}

	/**
	 * @param sectionID - the ID of the Section requested.
	 * @return Section - the Section associated with SectionID
	 * @throws Exception
	 */
	public Section getSection(int sectionID) throws WrongElementIDException, SystemFailureException {
		try {
			return (Section)this.getPersistent().getForumElement(sectionID, ForumElementType.SECTION);
		} catch (DataBaseIOException e) {
			throw new SystemFailureException(e);
		}
	}

	/**
	 * registers a user in the system, as long as the userName given is
	 * unique and legal and the password is legal
	 * @param userName - the user name given by the user to register
	 * @param password - the password selected by user for registering
	 * @return boolean - if the registration succeeded or not
	 * @throws UnAuthorizedException
	 */
	public abstract boolean register(String userName, String password) throws UnAuthorizedException, SystemFailureException;

	/**
	 * unregister a user from the system if userName is a legal user.
	 * @param userName - the user to remove
	 * @return if the user removed successfully
	 * @throws Exception
	 */
	public abstract boolean removeUser(String userName) throws Exception;

	/**
	 * logs the user into the system using a user name and password.
	 * once logged in the user acquires additional actions he can perform
	 * in the system according to his level.
	 * @param userName - the user name entered by the user
	 * @param password - the password entered by the user.
	 * @return AUserHandler - if the login is successful, an new handler is returned, matching the user level.
	 * @throws WrongPasswordException
	 */
	public abstract AUserHandler login(String userName, String password)
					throws WrongUserNameException,UnAuthorizedException,WrongPasswordException, DataBaseIOException;

	/**
	 * logs out the user from the system, making him on a guest level again,
	 * until the next login.
	 * @param session
	 * @return AUserHandler - if the login is successful, returns an initiated guest handler
	 */
	public abstract AUserHandler logout(Session session) throws Exception;

	/**
	 * @param oldPass
	 * @param newPass
	 * @return
	 */
	public abstract boolean changePassword(String oldPass, String newPass) throws Exception;

	/**
	 * creates a new forum Section with a given name in an existing section with the given users as moderators
	 * @param parentSectionID - the ID of the parent Section in which the new Section will be created.
	 * @param sectionName - the name for the new section.
 	 * @param moderators - users who granted by the Admin as this section moderators
	 * @return Section - the new Section created.
	 * @throws UnAuthorizedException
	 */
	public abstract Section createSection(int parentSectionID, String sectionName, Collection<String> moderators) throws Exception;

	/**
	 * add moderator to existing Section.
	 * if the user is of type MEMBER only, updates his type to MODERATOR
	 * @param sectionID - the section for it the moderator will be added
	 * @param userName - the new moderator userName
	 * @return the updated Section
	 * @throws UnAuthorizedException
	 * @throws SystemFailureException
	 * @throws WrongUserNameException
	 * @throws WrongElementIDException
	 */
	public abstract Section addModeratorToSection(int sectionID, String userName) throws UnAuthorizedException, WrongElementIDException,
					WrongUserNameException, SystemFailureException;

	/**
	 * @param sectionID - the section from it the moderator will be removed
	 * @param userName - the moderator userName
	 * @return the updated Section
	 */
	public abstract Section removeModerator(int sectionID, String userName) throws WrongUserNameException, WrongElementIDException, SystemFailureException, UnAuthorizedException;

	/**
	 * remove Section and all of his subSections and topics. only performed by an Admin.
	 * @param sectionID - the section to remove
	 * @return the parent section of the removed section
	 * @throws UnAuthorizedException
	 */
	public abstract Section removeSection(int sectionID) throws Exception;

	/**
	 * creates a new Topic with a given headline and body in a section recognized be it's ID
	 * @param parentSectionID - the ID of the Section in which the new topic will be posted.
	 * @param messageHeadline - the headline of the new topic
	 * @param messageBody - the body of the new topic
	 * @return Topic - the Topic created.
	 * @throws UnAuthorizedException
	 */
	public abstract Topic createTopic(int parentSectionID, String messageHeadline, String messageBody) throws Exception;

	/**
	 * adds a new Message with headLine and body in an existing Topic.
	 * @param TopicID - the ID of the topic the message will be created in.
	 * @param messageHeadline - the headline of the new message.
	 * @param messageBody - the body of the new message.
	 * @return Topic - the updated Topic with the additional message in it.
	 * @throws UnAuthorizedException
	 */
	public abstract Topic addMessageToTopic(int topicID, String messageHeadline, String messageBody) throws Exception;

	/**
	 * allows a user to change the contents of a message he wrote
	 * @param topicID - the ID of the topic in which the message to change
	 * @param messageToEditID - the ID of the message to edit
	 * @param messageHeadLine - the new headline for the message.
	 * @param messageBody - the new body for the message
	 * @return Topic - the Topic updated with the edited message.
	 * @throws UnAuthorizedException
	 */
	public abstract Topic editMessage(int topicID, int messageToEditID, String messageHeadLine, String messageBody) throws Exception;

	/**
	 * remove message from the forum.
	 * @param messageID - the ID of the message to remove
	 * @return if the message is the only message in a topic, returns the updated Section (without the removed topic)
	 * 		   else - returns the Topic updated with the rest of the messages.
	 * @throws UnAuthorizedException
	 */
	public abstract AForumElement deleteMessage(int parentTopicID, int messageToDeleteID) throws Exception;

	/**
	 * Determines if the current user is allowed to edit a specific message
	 * @param messageToEdit The message to edit
	 * @param sectionID the section which the message is in
	 * @return true, if allowed to edit the message
	 */
	public abstract boolean editMessageAuthentication(Message messageToEdit, int sectionID) throws SystemFailureException;

	/**
	 * determines if the user is authorized to delete the message
	 * @param messageToDelete - the message to delete
	 * @param sectionID - the section in which the message is in
	 * @return true if the user is authorized to delete
	 */
	public abstract boolean deleteMessageAuthentication(Message messageToDelete, int sectionID) throws SystemFailureException;


	/**
	 * determines if the user is authorized to delete a section
	 * @return true if the user is authorized to delete
	 * @throws Exception
	 */
	public abstract boolean editSectionAuthentication();



	/**
	 * make an image of the statistic diagram showing how many user was online in each hour of 'date'
	 * @param date - the requested day
	 * @return - the path of the diagram jpeg image on the local machine
	 */
	public abstract BufferedImage makeUserCountStatistics(Date date) throws Exception;



	/**
	 * make an image of the statistic diagram showing how many message posted each hour of 'date'
	 * @param date - the requested day
	 * @return - the path of the diagram jpeg image on the local machine
	 */
	public abstract BufferedImage makeMessageCountStatistics(Date date) throws Exception;

	/**
	 * make an image of the statistic diagram showing how many message 'user' posted each day for 31 days,
	 * starting 'fromDate'
	 * @param fromDate - the starting date
	 * @param user - the user on which the diagram is about
	 * @return - the path of the diagram jpeg image on the local machine
	 */
	public abstract BufferedImage makeUserMessagePerDay(Date fromDate, String user) throws Exception;


	public int getNumOfUsers(){
		return SessionManager.getInstance().getCurrentOnline();
	}

	public Vector<String> getAllUsernames() {
		return this.getPersistent().getUsernameList();
	}

	public abstract Vector<String> getManagedUsernames();

	/**
	 * @return persistent.
	 */
	public IPersistentHandler getPersistent() {
		return persistent;
	}

}
